package net.cardgame.oraclecard.service;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import jp.jma.oraclecard.R;

import net.cardgame.orcalecard.bean.DeckBean;
import net.cardgame.orcalecard.pref.SecurePreferences;
import net.cardgame.orcalecard.utils.ConstantValue;
import net.cardgame.orcalecard.utils.FileUtils;
import net.cardgame.orcalecard.utils.Utils;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class ServiceDownload extends IntentService implements
		ServiceDownloadListener {
	public final static String KEY_PATH_SERVER = "path_server";
	public final static String KEY_DECK_ID = "deckBeanId";
	public final static String KEY_POSITION = "Position";
	public final static String KEY_PERCENT = "percent download";
	public final static String KEY_PATH_SAVE = "path save";
	public final static String KEY_STATUS = "status download";
	public final static String KEY_MESSAGE_FULL_MEMORY = "full_memory";
	private static DownloadUnzipObject downloadObject1;
	private static DownloadUnzipObject downloadObject2;
	private static boolean cancel = false;

	public ServiceDownload(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}

	public ServiceDownload() {
		super("ServiceDownload");
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		// TODO Auto-generated method stub
		// Get data
		Bundle bundle = intent.getExtras();
		cancel = false;
		if (bundle.containsKey("cancel")) {
			cancel = true;
			return;
		}
		String patch = bundle.getString(KEY_PATH_SERVER);
		int deckId = bundle.getInt(KEY_DECK_ID);
		int position = bundle.getInt(KEY_POSITION);
		String patchSave = bundle.getString(KEY_PATH_SAVE);
		DownloadUnzipObject object = new DownloadUnzipObject(deckId, position,
				patch, patchSave);

		boolean excute = false;
		if (downloadObject1 == null) {
			if (downloadObject2 == null
					|| (downloadObject2 != null && object.getDeckId() != downloadObject2
							.getDeckId())) {
				downloadObject1 = object;
				excute = true;
			}
		} else if (downloadObject2 == null
				&& downloadObject1.getDeckId() != object.getDeckId()) {
			downloadObject2 = object;
			excute = true;
		}
		if (excute) {
			// excute download and unzip file
			DownloadFileAndUnzip ayncTask = new DownloadFileAndUnzip(this);
			ayncTask.execute(object);
		}
	}

	/* This task implement Download Deck bean from server */
	class DownloadFileAndUnzip extends
			AsyncTask<DownloadUnzipObject, Void, DownloadUnzipObject> {
		/**
		 * Downloading file in background thread
		 * */
		private final static int CONNECT_TIMEOUT = 15 * 1000;
		private final static int READ_TIMEOUT = 30 * 1000;
		private Context mContext;
		FileUtils fileUtils;

		DownloadFileAndUnzip(Context context) {
			mContext = context;
		}

		@Override
		protected DownloadUnzipObject doInBackground(
				DownloadUnzipObject... progress) {
			DownloadUnzipObject downloadObject = progress[0];
			long downloaded = 0;
			try {
				File folder = new File(
						ConstantValue.getPatchCardData(ServiceDownload.this));
				if (!folder.exists()) {
					folder.mkdirs();
				}
				File file = new File(downloadObject.getPathSaveFile());
				URL url = new URL(downloadObject.getUrlDownload());
				HttpURLConnection connection = (HttpURLConnection) url
						.openConnection();
				connection.setReadTimeout(READ_TIMEOUT);
				connection.setConnectTimeout(CONNECT_TIMEOUT);
				if (file.exists()) {
					downloaded = (int) file.length();
				}
				long fileLength = 0;
				if (downloaded > 0) {
					fileLength = connection.getContentLength();
					if (downloaded >= fileLength) {
						downloadObject.setPercent(50);
						// perform unzip file
						FileUtils fileUtils = new FileUtils();
						fileUtils.registryUnzipListener(ServiceDownload.this);
						if (fileUtils.unzipFile(downloadObject))
							downloadObject.setFinished();
						return downloadObject;
					} else {
						connection.disconnect();
						url = new URL(downloadObject.getUrlDownload());
						connection = (HttpURLConnection) url.openConnection();
						connection.setReadTimeout(READ_TIMEOUT);
						connection.setConnectTimeout(CONNECT_TIMEOUT);
					}
				}
				connection.setRequestProperty("Range", "bytes=" + downloaded
						+ "-");
				connection.setDoOutput(true);
				BufferedInputStream in = new BufferedInputStream(
						connection.getInputStream());
				FileOutputStream fos = downloaded == 0 ? new FileOutputStream(
						file) : new FileOutputStream(
						downloadObject.getPathSaveFile(), true);

				BufferedOutputStream bout = new BufferedOutputStream(fos, 1024);
				byte[] data = new byte[1024];
				long lenghtOfFile = connection.getContentLength() + downloaded;
				if (!FileUtils.availableDownload(lenghtOfFile)) {
					// Bộ nhớ không đủ, không cho phép download
					String message1 = getResources().getString(
							R.string.freespace_unvailable1);
					String message2 = getResources().getString(
							R.string.freespace_unvailable2);
					String message = message1 + 3 * lenghtOfFile
							/ (1024 * 1024) + message2;
					// send broadcast receiver
					Intent intent = new Intent(ConstantValue.ACTION_DOWNLOAD);
					intent.putExtra(KEY_MESSAGE_FULL_MEMORY, message);
					LocalBroadcastManager.getInstance(ServiceDownload.this)
							.sendBroadcast(intent);
					return downloadObject;
				}
				int count;
				int percent = 0;
				while ((count = in.read(data, 0, 1024)) != -1) {
					if (cancel)
						return downloadObject;
					downloaded += count;
					float result = (float) downloaded / (float) lenghtOfFile
							* 100;
					result = result / 2;
					if (result - percent >= 1) {
						downloadObject.setPercent((int) result);
						// send progress percentage to broadcast
						Intent intent = new Intent(
								ConstantValue.ACTION_DOWNLOAD);
						intent.putExtra(KEY_DECK_ID, downloadObject.getDeckId());
						intent.putExtra(KEY_POSITION,
								downloadObject.getPosition());
						intent.putExtra(KEY_PERCENT,
								downloadObject.getPercent());
						LocalBroadcastManager.getInstance(ServiceDownload.this)
								.sendBroadcast(intent);
						// publishProgress(downloadObject);
						percent = (int) result;
					}
					bout.write(data, 0, count);
				}
				bout.flush();
				bout.close();
				in.close();
				connection.disconnect();
			} catch (Exception e) {
				Log.e("Error: ", e.toString());
				return downloadObject;
			}
			downloadObject.setPercent(50);
			// perform unzip file
			fileUtils = new FileUtils();
			fileUtils.registryUnzipListener(ServiceDownload.this);
			Timer timer = new Timer();
			timer.schedule(new TimerTask() {
				@Override
				public void run() {
					// TODO Auto-generated method stub
					if (cancel)
						fileUtils.stopUnzip();
				}
			}, 1000, 1000);
			if (fileUtils.unzipFile(downloadObject))
				downloadObject.setFinished();
			timer.cancel();
			return downloadObject;
		}

		@Override
		protected void onPostExecute(DownloadUnzipObject result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			if (downloadObject1 != null
					&& result.getDeckId() == downloadObject1.getDeckId()) {
				downloadObject1 = null;
			} else {
				downloadObject2 = null;
			}
			// send to broadcast receiver
			Intent intent = new Intent(ConstantValue.ACTION_DOWNLOAD);
			intent.putExtra(KEY_DECK_ID, result.getDeckId());
			intent.putExtra(KEY_POSITION, result.getPosition());
			intent.putExtra(KEY_PERCENT, result.getPercent());
			intent.putExtra(KEY_STATUS, result.isFinished());
			LocalBroadcastManager.getInstance(ServiceDownload.this)
					.sendBroadcast(intent);
			saveStatus(result);

		}

		void saveStatus(DownloadUnzipObject object) {
			SecurePreferences appPreferences = new SecurePreferences(mContext,
					ConstantValue.APP_PREFERENCES,
					ConstantValue.PREFERENCES_SECRET_KEY, true);
			Gson gson = new Gson();
			Type listOfDeckBean = new TypeToken<ArrayList<DeckBean>>() {
			}.getType();
			String listSaved = appPreferences
					.getString(ConstantValue.CONFIG_DECKBEAN_KEY);
			ArrayList<DeckBean> listDeckBean = gson.fromJson(listSaved,
					listOfDeckBean);
			for (DeckBean deckBean : listDeckBean) {
				if (deckBean.deckId == object.getDeckId()) {
					deckBean.percentDownloaded = object.isFinished() ? -2
							: object.getPercent();
					if (!deckBean.isFree) {
						deckBean.isUnlock = true;
					}
					ArrayList<DeckBean> listSave = checkUnlockSpecial(listDeckBean);
					String save = gson.toJson(listSave, listOfDeckBean);
					appPreferences.put(ConstantValue.CONFIG_DECKBEAN_KEY, save);
					return;
				}
			}
		}

		ArrayList<DeckBean> checkUnlockSpecial(ArrayList<DeckBean> listDeckBean) {
			int total = 0;
			for (DeckBean deckbean : listDeckBean) {
				if (deckbean.percentDownloaded == -2)
					total++;
				if (total >= 2)
					return unlockSpecialAndRandom(listDeckBean);
			}
			return listDeckBean;
		}

		ArrayList<DeckBean> unlockSpecialAndRandom(
				ArrayList<DeckBean> listDeckBean) {
			for (DeckBean deckbean : listDeckBean) {
				if (deckbean.deckId == 999 || deckbean.deckId == 998) {
					deckbean.isUnlock = true;
				}
			}
			return listDeckBean;
		}
	}

	@Override
	public void onUpdateProgressListener(int percent, int position, int deckId) {
		// TODO Auto-generated method stub
		Intent intent = new Intent(ConstantValue.ACTION_DOWNLOAD);
		// Add data
		intent.putExtra(KEY_DECK_ID, deckId);
		intent.putExtra(KEY_POSITION, position);
		intent.putExtra(KEY_PERCENT, percent);
		LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
	}

	@Override
	public void onDownloadFailListener(DownloadUnzipObject object,
			String message) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onFinishedListener(DownloadUnzipObject object) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
	}
}
